#pragma once

#include "loirey_MyMath.h"

namespace loirey
{
	class CMyNormalizer
	{
	public:
		virtual ~CMyNormalizer() { }
	protected:
		virtual double _Normalize(double* pData, size_t Length) = 0;
	public:
		virtual CMyNormalizer* myClone() = 0;
		double Normalize(double* pData, size_t Length)
		{
			return _Normalize(pData, Length);
		}
		double Normalize(CSimpleTypeArray<double>& Data)
		{
			return _Normalize(Data.pElement, Data.Size);
		}
	};

	class CMyNormalizer_L2_NORM : public CMyNormalizer
	{
	public:
		double eps;
	public:
		CMyNormalizer_L2_NORM(double eps = EPS)
		{
			this->eps = eps;
		}
		virtual CMyNormalizer* myClone()
		{
			return new CMyNormalizer_L2_NORM(*this);
		}
	protected:
		virtual double _Normalize(double* pData, size_t Length)
		{
			size_t i;
			double* pd;
			double ret = eps * Length;
			pd = pData;
			for ( i = 0; i < Length; ++i, ++pd )
				ret += *pd * *pd;
			ret = sqrt(ret);
			pd = pData;
			for ( i = 0; i < Length; ++i, ++pd )
				*pd /= ret;
			return ret;
		}
	};

	class CMyNormalizer_Sum : public CMyNormalizer
	{
	public:
		bool fIsDataLogarithm;
	public:
		CMyNormalizer_Sum(bool fIsDataLogarithm)
		{
			this->fIsDataLogarithm = fIsDataLogarithm;
		}
		virtual CMyNormalizer_Sum* myClone()
		{
			return new CMyNormalizer_Sum(*this);
		}
	protected:
		virtual double _Normalize(double* pData, size_t Length)
		{
			size_t i;
			double* pd;
			double ret;

			if (fIsDataLogarithm)
			{
				ret = -MAXIMUM_DOUBLE_NUM_V;
				pd = pData;
				for ( i = 0; i < Length; ++i, ++pd )
					ret = CMyMath::log_Sum(ret, *pd);
				pd = pData;
				for ( i = 0; i < Length; ++i, ++pd )
					*pd = CMyMath::log_Product(*pd, -ret);
			}
			else
			{
				ret = 0.0;
				pd = pData;
				for ( i = 0; i < Length; ++i, ++pd )
					ret += *pd;
				if (ret < MINIMUM_DOUBLE_EPS_C) ret = 1.0;
				pd = pData;
				for ( i = 0; i < Length; ++i, ++pd )
					*pd /= ret;
			}

			return ret;
		}
	};
}

